#pragma once 

template <typename Type> class SLLIter;
template<typename Type>
class SLList
{
	struct node
	{
		Type data;
		node *next;
		node(const Type& d, node *k):data(d), next(k) {};
	};

	friend class SLLIter<Type>;
	node *head;
	unsigned int count;
public:

	SLList() : head(0) {count = 0;}

	~SLList();

	SLList<Type>& operator=(const SLList<Type>& that);

	SLList(const SLList<Type>& that);

	void addHead(const Type& v);

	void clear();

	void insert(SLLIter<Type>& index, const Type& v);

	void remove(SLLIter<Type>& index);

	inline unsigned int size() const
	{
		return count;
	}
};

template <typename Type>
SLList<Type>::~SLList()
{
	node *temp;
	while(head!=0)
	{
		temp = head;
		head = head->next;
		delete temp;
	}
	count = 0;
	delete head;
}

template <typename Type>
SLList<Type>& SLList<Type>::operator =(const SLList &that)
{
	if(this!= &that)
	{	
		this->clear();	
		if(that.head!=0)
		{
					
			node* rhs, *lhs;
			rhs = that.head;
			addHead(rhs->data);
			lhs = head;
			rhs = rhs->next;
			while(rhs != NULL)
			{
				lhs->next = new node(rhs->data, 0);
				lhs = lhs->next;
				rhs = rhs->next;
				count++;
			}
		}
	}
	return*this;
}

template <typename Type>
SLList<Type>::SLList(const SLList<Type>& that)
{
	head = 0;
	count = 0;		
	if(that.head!=NULL)
	{
		node* rhs, *lhs;
		rhs = that.head;
		addHead(rhs->data);
		lhs = head;
		rhs = rhs->next;
		while(rhs != 0)
		{
			lhs->next = new node(rhs->data, 0);
			lhs = lhs->next;
			rhs = rhs->next;
			count++;
		}
	}
}

template <typename Type>
void SLList<Type>::addHead(const Type &v)
{
	node *temp = new node(v, head);
	head = temp;
	count++;
}

template <typename Type>
void SLList<Type>::clear()
{	
	node *tmp;
	while(head!=0)
	{
		tmp = head;
		head = head->next;
		delete tmp;
	}
	count = 0;
}

template <typename Type>
void SLList<Type>::insert(SLLIter<Type>& index, const Type& v)
{
	if(index.curr!=NULL)
	{
		node *temp = new node(v,index.curr);
		if(index.prev != 0)
		{
			index.prev->next = temp;
			index.curr = temp;
		}
		else
		{
			head = temp;
			index.curr = head;
		}
		count++;
	}
}

template <typename Type>
void SLList<Type>::remove(SLLIter<Type>& index)
{
	if(index.curr!=0)
	{
		if(index.curr == head)
		{
			head = index.curr->next;
			delete index.curr;
			index.curr = head;
		}
		else
		{
			index.prev->next = index.curr->next;
			delete index.curr;
			index.curr = index.prev->next;
		}
		count--;
	}
}

template <typename Type>
class SLLIter
{
	friend class SLList<Type>;
	SLList<Type> *temp;
	typename SLList<Type>::node *prev, *curr;
	
public:	
	SLLIter(SLList<Type>& listToIterate)
	{
		temp = &listToIterate;
		curr = temp->head;
		prev = 0;
	}

	void begin()
	{
		curr = temp->head;
		prev = 0;
	}

	bool end() const
	{
		return (curr==0);
	}

	bool checkifvalid() const
	{
		if(curr)
		return false;
	else
		return true;
	}

	SLLIter<Type>& operator++()
	{
		if(curr!=0)
		{
			prev = curr;
			curr = curr->next;
		}
		return*this;
	}

	Type& current() const
	{
		return curr->data;
	}
};

